/**
 * Created by Yu Jin Xian on 2016/12/22.
 */
function factoryPattern() {
    function createPerson(name, age, job) {
        var o = new Object();
        o.name = name;
        o.age = age;
        o.job = job;

        o.sayName = function () {
            alert(this.name);
        };

        return o;
    }

    var person1 = createPerson('Nicholas', 29, 'Software Engineer');
    var person2 = createPerson('Greg', 27, 'Doctor');
}

function constructorPattern() {
    function Person(name, age, job) {
        this.name = name;
        this.age = age;
        this.job = job;

        this.sayName = function () {
            alert(this.name);
        };
    }

    var person1 = new Person('Nicholas', 29, 'Software Engineer');
    var person2 = new Person('Greg', 27, 'Doctor');

    alert(person1.constructor == Person);           // true
    alert(person2.constructor == Person);           // true

    alert(person1 instanceof Object);               // true
    alert(person1 instanceof Person);               // true
    alert(person2 instanceof Object);               // true
    alert(person2 instanceof Person);               // true

    function constructor() {
        // 当作构造函数使用
        var person1 = new Person('Nicholas', 29, 'Software Engineer');
        var person2 = new Person('Greg', 27, 'Doctor');

        // 做为普通函数调用
        Person('Greg', 27, 'Doctor');               // 添加到 window
        window.sayName();                           // 'Greg'

        // 在另一个对象的作用域中调用
        var o = new Object();
        Person.call(o, 'Kristen', 25, 'Nurse');
        o.sayName();
    }

    function issue() {
        function Person(name, age, job) {
            this.name = name;
            this.age = age;
            this.job = job;
            // 与声明函数在逻辑上是等价的
            this.sayName = new Function("alert(this.name");
        }

        var person1 = new Person('Nicholas', 29, 'Software Engineer');
        var person2 = new Person('Greg', 27, 'Doctor');
        alert(person1.sayName == person2.sayName);  // false

        function good() {
            function Person(name, age, job) {
                this.name = name;
                this.age = age;
                this.job = job;
                this.sayName = sayName;
            }

            function sayName() {
                alert(this.name);
            }

            var person1 = new Person('Nicholas', 29, 'Software Engineer');
            var person2 = new Person('Greg', 27, 'Doctor');
        }
    }
}

function prototypePattern() {
    function Person() {

    }

    Person.prototype.name = 'Nicholas';
    Person.prototype.age = 27;
    Person.prototype.job = 'Software Engineer';
    Person.prototype.sayName = function () {
        alert(this.name);
    };

    var person1 = new Person();
    person1.sayName();                              // "Nicholas"

    var person2 = new Person();
    person2.sayName();                              // "Nicholas"


    function understandingPrototype() {
        alert(Perosn.prototype.isPrototypeOf(person1)); // true
        alert(Perosn.prototype.isPrototypeOf(person2)); // true

        alert(Object.getPrototypeOf(person1) == Person.prototype);  // true
        alert(Object.getPrototypeOf(person2).name);                 // "Nicholas"

        person1.name = 'Grey';
        alert(person1.name);                        // "Grey" 来自实例
        alert(person2.name);                        // "Nicholas" 来自原型

        delete person1.name;
        alert(person1.name);                        // "Nicholas" 来自原型

        alert(person1.hasOwnProperty('name'));      // false

        person1.name = 'Greg';
        alert(person1.name);                        // "Greg" 来自原型
        alert(person1.hasOwnProperty('name'));      // true

        alert(person2.name);                        // "Nicholas"
        alert(person2.hasOwnProperty('name'));      // false

        delete person1.name;
        alert(person1.name);                        // "Nicholas"
        alert(person1.hasOwnProperty('name'));      // false
    }

    function prototypeWithInOperator() {
        alert(person1.hasOwnProperty('name'));      // false
        alert('name' in person1);                   // true

        person1.name = 'Greg';
        alert(person1.name);
        alert(person1.hasOwnProperty('name'));
        alert('name' in person1);

        alert(person2.name);                        // "Nicholas" 来自原型
        alert(person2.hasOwnProperty('name'));      // false
        alert('name' in person2);                   // true

        delete person1.name;
        alert(person1.name);                        // "Nicholas" 来自原型
        alert(person1.hasOwnProperty('name'));      // false
        alert('name' in person1);                   // true

        function hasPrototyProperty(object, name) {
            return !object.hasOwnProperty(name) && (name in object);
        }

        var person = new Person();
        alert(hasPrototyProperty(person, 'name'));  // true

        person.name = 'Greg';
        alert(hasPrototyProperty(person, 'name'));  // false

        function iebug() {
            var o = {
                toString: function () {
                    return 'My Object';
                }
            };

            for (var prop in o) {
                if (prop == 'toString') {
                    alert('Found toString');        // 在 >=IE8 中不会显示
                }
            }
        }

        function objectKeys() {
            var keys = Object.keys(Person.prototype);
            alert(keys);                            // "name,age,job,sayName"

            var p1 = new Person();
            p1.name = 'Rob';
            p1.age = 31;
            var p1Keys = Object.keys(p1);
            alert(p1Keys);                          // "name,age"
        }

        function objectPropertyNames() {
            var keys = Object.getOwnPropertyNames(Person.prototype);
            alert(keys);                            // "constructor,name,age,job,sayName"
        }
    }

    function simplerPrototypeMethods() {
        function Person() {

        }

        Person.prototype = {
            name: 'Nicholas',
            age: '29',
            job: 'Software Enginner',
            sayName: function () {
                alert(this.name);
            }
        };

        var friend = new Person();

        alert(friend instanceof Object);            // true
        alert(friend instanceof Person);            // true
        alert(friend.constructor == Person);        // false
        alert((friend.constructor == Object));      // true

        Person.prototype = {
            constructor: Person,
            name: 'Nicholas',
            age: '29',
            job: 'Software Enginner',
            sayName: function () {
                alert(this.name);
            }
        };

        function or() {
            Object.defineProperty(
                Person.prototype,
                'constructor',
                { enumerable: false, value: Person });
        }
    }

    function dynamicPrototype() {
        var friend = new Person();

        Person.prototype.sayHi = function () {
            alert('hi');
        };

        friend.sayHi();                             // "hi" (没有问题)

        function error() {
            function Person() {

            }

            var friend = new Person();

            Person.prototype = {
                constructor: Person,
                name: 'Nicholas',
                age: '29',
                job: 'Software Enginner',
                sayName: function () {
                    alert(this.name);
                }
            };

            friend.sayName();                       // error
        }
    }

    function originalObjectPrototype() {
        alert(typeof Array.prototype.sort);         // "function"
        alert(typeof String.prototype.substring);   // "function"

        String.prototype.startsWith = function (text) {
            return this.indexOf(text) == 0;
        };

        var msg = "Hello world!";
        alert(msg.startsWith("Hello"));             // true
    }

    function problemOfPrototype() {
        function Person() {

        }

        Person.prototype = {
            constructor: Person,
            name: 'Nicholas',
            age: '29',
            job: 'Software Enginner',
            friends: ['Shelby', 'Court'],
            sayName: function () {
                alert(this.name);
            }
        };

        var person1 = new Person();
        var person2 = new Person();

        person1.friends.push('Van');

        alert(person1.friends);                     // "Shelby,Court,Van"
        alert(person2.friends);                     // "Shelby,Court,Van"
        alert(person1.friends === person2.friends); // true
    }
}

function useConstructorPatternAndPrototypePattern() {
    function Person(name, age, job) {
        this.name = name;
        this.age = age;
        this.job = job;
        this.friends = ['Shelby', 'Court'];
    }

    Person.prototype = {
        constructor: Person,
        sayName: function () {
            alert(this.name);
        }
    };

    var person1 = new Person('Nicholas', 29, 'Software Enginner');
    var person2 = new Person('Greg', 27, 'Doctor');

    person1.friends.push('van');
    alert(person1.friends);                         // "Shelby,Court,Van"
    alert(person2.friends);                         // "Shelby,Court,Van"
    alert(person1.friends === person2.friends);     // false
    alert(person1.sayName === person2.sayName);     // true
}

function dynamicPrototypePattern() {
    function Person(name, age, job) {
        this.name = name;
        this.age = age;
        this.job = job;

        if (typeof this.sayName != 'function') {
            Person.prototype.sayName = function () {
                alert(name);
            }
        }
    }

    var friend = new Person('Nicholas', 29, 'Software Enginner');
    friend.sayName();
}

function parasiticConstructorPattern() {
    function Person(name, age, job) {
        var o = new Object();
        o.name = name;
        o.age = age;
        o.job = job;
        o.sayName = function () {
            alert(this.name);
        };
        return o;
    }

    var friend = new Person('Nicholas', 29, 'Software Enginner');
    friend.sayName();

    function SpecialArray() {
        // 创建数组
        var values = new Array();
        // 添加值
        values.push.apply(values, arguments);
        // 添加方法
        values.toPipedString = function () {
            return this.join('|');
        };
        return values;
    }

    var colors = new SpecialArray('red', 'blue', 'green');
    alert(colors.toPipedString());                  // "red|blue|green"
}

function durableConstructorPattern() {
    function Person(name, age, job) {
        // 创建要返回的对象
        var o = new Object();
        // 可以在这里定义私有变量和函数
        o.sayName = function () {
            alert(name);
        };
        // 返回对象
        return o;
    }

    var friend = Person('Nicholas', 29, 'Software Engineer')
}